functor Table (S : TABLE_STRUCTS) : TABLE =
struct
  open S
  
  structure T = Types
  
  structure Map = BinaryMapFn (type ord_key = Id.t
                               val compare = Id.compare)

  exception NotFound
  exception Duplicate
                                 
  type 'a t = 'a Map.map
  type tenv = T.t Map.map
  type venv = {tipe : T.t, fresh : Id.t} Map.map
  
  fun empty () = Map.empty
  fun enter (k, a, t) = Map.insert (t, k, a)
  fun look (k, t) = Map.find (t, k)
  fun looku (k, t) =
      let val a = Map.find (t, k)
      in  case a
           of NONE => raise NotFound 
            | SOME aa => aa
      end
  fun enteru (k, a, t) =
      let val aa = look (k, t)
      in  case aa
           of NONE => enter (k, a, t)
            | _ => raise Duplicate
      end
  
  fun enterList (l, t) = List.foldl (fn ((k, a), t0) => enter (k, a, t0)) t l
  
  fun toString (t, f) =
      let val new = Map.listItems t
      in  String.concat (List.map f new)
      end
        
  fun emptyTenv () : tenv = empty ()
  fun emptyVenv () : venv = empty ()
  
  fun baseTenv () : tenv = emptyTenv ()
  
  fun baseVenv () : venv = enterList ([(Id.fromString "printp",
                                        {tipe = T.Funct (T.Product [T.Ns], T.Voidt),
                                         fresh = Id.fromString "printp"}),
			               (Id.fromString "print", 
			                {tipe = T.Funct (T.Product [T.Intt], T.Voidt),
			                 fresh = Id.fromString "print"}),
			               (Id.fromString "printb",
			                {tipe = T.Funct (T.Product [T.Boolt], T.Voidt),
			                 fresh = Id.fromString "printb"})],
                                       emptyVenv ())
  
  fun tenvToString t = 
      let val map = T.toString 
      in  toString (t, map)
      end
  
  fun venvToString t = 
      let val map = fn {tipe, fresh} => T.toString tipe
      in  toString (t, map)
      end
end  
 